/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    sec.h
 *  @brief   Security Engine header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 ****************************************************************/

#ifndef __SEC_H__
#define __SEC_H__

#include <stdint.h>
#include "eocv100.h"
#include "bits.h"
#include "io.h"
#include "common.h"
#include "syscounter.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct sec_reg sec_reg_t, *sec_reg_t_ptr;

#define wait_cond_timeout(cond, timeout)                                \
        ({                                                              \
                int ret = 0;                                            \
                int _timeout = (timeout);                               \
                while (!(cond)) {                                       \
                        if (_timeout == 0) {                            \
                                ret = -1;                               \
                                break;                                  \
                        }                                               \
                        _timeout--;                                     \
                        syscnt_mdelay(1);                               \
                }                                                       \
                ret;                                                    \
        })

/* Security cfg */
#define SEC_REG_BASE_ADDR          MEM_MAP_SEC_CFG_BASE_ADDR

/* Security data */
#define SEC_DATA_BASE_ADDR         MEM_MAP_SEC_DATA_BASE_ADDR
/* Security input data */
#define SEC_IN_DATA_BASE_ADDR      SEC_DATA_BASE_ADDR
/* Security output data */
#define SEC_OUT_DATA_BASE_ADDR     (SEC_DATA_BASE_ADDR + 0x100)
/* Security HW key */
#define SEC_HW_KEY_DATA_BASE_ADDR  (SEC_DATA_BASE_ADDR + 0x1000)
/* Security random data */
#define SEC_RANDOM_DATA_BASE_ADDR  (SEC_DATA_BASE_ADDR + 0x1800)

#define SEC_REG_PTR()              ((sec_reg_t_ptr)SEC_REG_BASE_ADDR)

#define AES_ENCRYPT                BIT(0)
#define AES_DECRYPT                BIT(1)
#define SM4_ENCRYPT                BIT(2)
#define SM4_DECRYPT                BIT(3)
#define SHA256                     BIT(4)

/* update HW key, write to 1, then write 0 */
#define UPDATE_KEY                 BIT(8)

#define KEY_TYPE_POS               0
#define KEY_TYPE_LEN               1

#define SEC_MAX_DATA_LEN           256

/* Enable RNG */
#define RNG_SWITCH_ON              BIT(0)
/* Update RNG seed */
#define RNG_UPDATE_SEED            BIT(1)

/* RNG seed */
#define RNG_SEED_POS               0
#define RNG_SEED_LEN               20

/* SHA256 maximum length */
#define SHA256_MAXIMUM_LEN         0xfffffffc

#define ERROR_0                   BIT(0)
#define ERROR_1                   BIT(1)
#define ERROR_2                   BIT(2)
#define SEC_DONE                  BIT(8)
#define SEC_CFG                   BIT(16)

enum key_type {
	SW_KEY,
	HW_KEY,
};

struct sec_reg {
	__IOM reg_t cmd;        /* 0x00 */
	__IOM reg_t cfg;        /* 0x04 */
	__IOM reg_t sw_key[4];  /* 0x08 ~ 0x14*/
	__IOM reg_t rng;        /* 0x18 */
	__IOM reg_t rng_seed;   /* 0x1c */
	__IM  reg_t proc_len;   /* 0x20 */
	__IOM reg_t cmd_size;   /* 0x24 */
	__IOM reg_t rsvd[11];   /* 0x28 ~ 0x50 */
	__IOM reg_t mask;       /* 0x54 */
	__OM  reg_t icr;        /* 0x58 */
	__OM  reg_t isr;        /* 0x5c */
	__IM  reg_t mis;        /* 0x60 */
};

/* RNG */
void sec_en_rng(void);
void sec_dis_rng(void);
void sec_update_rng_seed(void);
void sec_set_rng_seed(int seed);
void sec_get_rng_data(u8 *rng, int rng_len);

/* Key */
void sec_update_hw_key(void);
void sec_get_hw_key(u8 *hw_key, int keylen);
void sec_set_key_type(enum key_type type);

/* AES */
int sec_aes_set_ek(const u8 *ek, int keylen);
int sec_aes_set_dk(const u8 *dk, int keylen);
int sec_aes_ecb_encrypt(const u8 *input, int length, u8 *output);
int sec_aes_ecb_decrypt(const u8 *input, int length, u8 *output);

/* SM4 */
int sec_sm4_set_ek(const u8 *ek, int keylen);
int sec_sm4_set_dk(const u8 *dk, int keylen);
int sec_sm4_ecb_encrypt(const u8 *input, int length, u8 *output);
int sec_sm4_ecb_decrypt(const u8 *input, int length, u8 *output);

/* SAH-256 */
int sec_sha256_compute(const u8 *data, u32 length, u8 *digest);

#ifdef __cplusplus
}
#endif

#endif /* __SEC_H__ */

